

<!DOCTYPE html>
<!--[if IE]><![endif]-->
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>React v15.4.0 - React Blog</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta property="og:title" content="React v15.4.0 - React Blog">
  <meta property="og:type" content="article">
  <meta property="og:url" content="https://facebook.github.io/react/blog/2016/11/16/react-v15.4.0.html">
  <meta property="og:image" content="https://facebook.github.io/react/img/logo_og.png">
  <meta property="og:description" content="Today we are releasing React 15.4.0.
">
  <meta property="fb:app_id" content="623268441017527">

  <link rel="shortcut icon" href="/react/favicon.ico">
  <link rel="alternate" type="application/rss+xml" title="React" href="https://facebook.github.io/react/feed.xml">

  <link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css" />
  <link rel="stylesheet" href="/react/css/syntax.css">
  <link rel="stylesheet" href="/react/css/codemirror.css">
  <link rel="stylesheet" href="/react/css/react.css">

  <script src="//use.typekit.net/vqa1hcx.js"></script>
  <script>try{Typekit.load();}catch(e){}</script>

  <!--[if lte IE 8]>
  <script src="https://unpkg.com/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://unpkg.com/es5-shim@4.5.9/es5-shim.min.js"></script>
  <script src="https://unpkg.com/es5-shim@4.5.9/es5-sham.min.js"></script>
  <![endif]-->
  <script src="https://unpkg.com/docsearch.js@1.5.0/dist/cdn/docsearch.min.js"></script>
  <script src="https://unpkg.com/codemirror@5.15.2"></script>
  <script src="https://unpkg.com/codemirror@5.15.2/mode/javascript/javascript.js"></script>
  <script src="https://unpkg.com/codemirror@5.15.2/mode/xml/xml.js"></script>
  <script src="https://unpkg.com/codemirror@5.15.2/mode/jsx/jsx.js"></script>
  <script src="https://unpkg.com/react/dist/react.min.js"></script>
  <script src="https://unpkg.com/react-dom/dist/react-dom.min.js"></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
  <script src="/react/js/live_editor.js"></script>
</head>
<body>

  <div class="container">

    <div class="nav-main">
  <div class="wrap">
    <a class="nav-home" href="/react/">
      <img class="nav-logo" src="/react/img/logo.svg" width="36" height="36">
      React
    </a>
    <div class="nav-lists">
      <ul class="nav-site nav-site-internal">
        <li><a href="/react/docs/hello-world.html">Docs</a></li>
        <li><a href="/react/tutorial/tutorial.html">Tutorial</a></li>
        <li><a href="/react/community/support.html">Community</a></li>
        <li><a href="/react/blog/" class="active">Blog</a></li>
        <li class="nav-site-search">
          <input id="algolia-doc-search" type="text" placeholder="Search docs..." />
        </li>
      </ul>
      <ul class="nav-site nav-site-external">
        <li><a href="https://github.com/facebook/react">GitHub</a></li>
        <li><a href="https://github.com/facebook/react/releases">v15.5.4</a></li>
      </ul>
    </div>
  </div>
</div>


    <section class="content wrap blogContent">

  <div class="inner-content">
    

<h1>

  React v15.4.0

</h1>

<p class="meta">
  November 16, 2016
  by
  
    
      <a href="https://twitter.com/dan_abramov">Dan Abramov</a>
    
    
  
</p>

<hr>

<div class="post">
  <p>Today we are releasing React 15.4.0.</p>

<p>We didn&#39;t announce the <a href="https://github.com/facebook/react/blob/master/CHANGELOG.md#1510-may-20-2016">previous</a> <a href="https://github.com/facebook/react/blob/master/CHANGELOG.md#1520-july-1-2016">minor</a> <a href="https://github.com/facebook/react/blob/master/CHANGELOG.md#1530-july-29-2016">releases</a> on the blog because most of the changes were bug fixes. However, 15.4.0 is a special release, and we would like to highlight a few notable changes in it.</p>

<h3>Separating React and React DOM</h3>

<p><a href="/react/blog/2015/09/10/react-v0.14-rc1.html#two-packages-react-and-react-dom">More than a year ago</a>, we started separating React and React DOM into separate packages. We deprecated <code>React.render()</code> in favor of <code>ReactDOM.render()</code> in React 0.14, and removed DOM-specific APIs from <code>React</code> completely in React 15. However, the React DOM implementation still <a href="https://www.reddit.com/r/javascript/comments/3m6wyu/found_this_line_in_the_react_codebase_made_me/cvcyo4a/">secretly lived inside the React package</a>.</p>

<p>In React 15.4.0, we are finally moving React DOM implementation to the React DOM package. The React package will now contain only the renderer-agnostic code such as <code>React.Component</code> and <code>React.createElement()</code>.</p>

<p>This solves a few long-standing issues, such as <a href="https://github.com/facebook/react/issues/7386">errors</a> when you import React DOM in the same file as the <a href="https://facebook.github.io/jest/blog/2016/07/27/jest-14.html">snapshot testing</a> renderer.</p>

<p><strong>If you only use the official and documented React APIs you won&#39;t need to change anything in your application.</strong></p>

<p>However, there is a possibility that you imported private APIs from <code>react/lib/*</code>, or that a package you rely on might use them. We would like to remind you that this was never supported, and that your apps should not rely on internal APIs. The React internals will keep changing as we work to make React better.</p>

<p>Another thing to watch out for is that React DOM Server is now about the same size as React DOM since it contains its own copy of the React reconciler. We don&#39;t recommend using React DOM Server on the client in most cases.</p>

<h3>Profiling Components with Chrome Timeline</h3>

<p>You can now visualize React components in the Chrome Timeline. This lets you see which components exactly get mounted, updated, and unmounted, how much time they take relative to each other.</p>

<p><center><img src="/react/img/blog/react-perf-chrome-timeline.png" width="651" height="228" alt="React components in Chrome timeline" /></center></p>

<p>To use it:</p>

<ol>
<li><p>Load your app with <code>?react_perf</code> in the query string (for example, <code>http://localhost:3000/?react_perf</code>).</p></li>
<li><p>Open the Chrome DevTools <strong>Timeline</strong> tab and press <strong>Record</strong>.</p></li>
<li><p>Perform the actions you want to profile. Don&#39;t record more than 20 seconds or Chrome might hang.</p></li>
<li><p>Stop recording.</p></li>
<li><p>React events will be grouped under the <strong>User Timing</strong> label.</p></li>
</ol>

<p>Note that the numbers are relative so components will render faster in production. Still, this should help you realize when unrelated UI gets updated by mistake, and how deep and how often your UI updates occur.</p>

<p>Currently Chrome, Edge, and IE are the only browsers supporting this feature, but we use the standard <a href="https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API">User Timing API</a> so we expect more browsers to add support for it.</p>

<h3>Mocking Refs for Snapshot Testing</h3>

<p>If you&#39;re using Jest <a href="https://facebook.github.io/jest/blog/2016/07/27/jest-14.html">snapshot testing</a>, you might have had <a href="https://github.com/facebook/react/issues/7371">issues</a> with components that rely on refs. With React 15.4.0, we introduce a way to provide mock refs to the test renderer. For example, consider this component using a ref in <code>componentDidMount</code>:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kr">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>

<span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">MyInput</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
  <span class="nx">componentDidMount</span><span class="p">()</span> <span class="p">{</span>
<span class="hll">    <span class="k">this</span><span class="p">.</span><span class="nx">input</span><span class="p">.</span><span class="nx">focus</span><span class="p">();</span>
</span>  <span class="p">}</span>

  <span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span>
      <span class="o">&lt;</span><span class="nx">input</span>
<span class="hll">        <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">node</span> <span class="o">=&gt;</span> <span class="k">this</span><span class="p">.</span><span class="nx">input</span> <span class="o">=</span> <span class="nx">node</span><span class="p">}</span>
</span>      <span class="o">/&gt;</span>
    <span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>With snapshot renderer, <code>this.input</code> will be <code>null</code> because there is no DOM. React 15.4.0 lets us avoid such crashes by passing a custom <code>createNodeMock</code> function to the snapshot renderer in an <code>options</code> argument:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kr">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">MyInput</span> <span class="nx">from</span> <span class="s1">&#39;./MyInput&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">renderer</span> <span class="nx">from</span> <span class="s1">&#39;react-test-renderer&#39;</span><span class="p">;</span>

<span class="hll"><span class="kd">function</span> <span class="nx">createNodeMock</span><span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
</span><span class="hll">  <span class="k">if</span> <span class="p">(</span><span class="nx">element</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="s1">&#39;input&#39;</span><span class="p">)</span> <span class="p">{</span>
</span><span class="hll">    <span class="k">return</span> <span class="p">{</span>
</span><span class="hll">      <span class="nx">focus</span><span class="p">()</span> <span class="p">{},</span>
</span><span class="hll">    <span class="p">};</span>
</span><span class="hll">  <span class="p">}</span>
</span><span class="hll">  <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
</span><span class="hll"><span class="p">}</span>
</span>
<span class="nx">it</span><span class="p">(</span><span class="s1">&#39;renders correctly&#39;</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="kr">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span><span class="nx">createNodeMock</span><span class="p">};</span>
<span class="hll">  <span class="kr">const</span> <span class="nx">tree</span> <span class="o">=</span> <span class="nx">renderer</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="o">&lt;</span><span class="nx">MyInput</span> <span class="o">/&gt;</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
</span>  <span class="nx">expect</span><span class="p">(</span><span class="nx">tree</span><span class="p">).</span><span class="nx">toMatchSnapshot</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div>
<p>We would like to thank <a href="https://github.com/Aweary">Brandon Dail</a> for implementing this feature.</p>

<p>You can learn more about snapshot testing in <a href="https://facebook.github.io/jest/blog/2016/07/27/jest-14.html">this Jest blog post</a>.</p>

<hr>

<h2>Installation</h2>

<p>We recommend using <a href="https://yarnpkg.com/">Yarn</a> or <a href="https://www.npmjs.com/">npm</a> for managing front-end dependencies. If you&#39;re new to package managers, the <a href="https://yarnpkg.com/en/docs/getting-started">Yarn documentation</a> is a good place to get started.</p>

<p>To install React with Yarn, run:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash">yarn add react@15.4.0 react-dom@15.4.0
</code></pre></div>
<p>To install React with npm, run:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash">npm install --save react@15.4.0 react-dom@15.4.0
</code></pre></div>
<p>We recommend using a bundler like <a href="https://webpack.js.org/">webpack</a> or <a href="http://browserify.org/">Browserify</a> so you can write modular code and bundle it together into small packages to optimize load time.</p>

<p>Remember that by default, React runs extra checks and provides helpful warnings in development mode. When deploying your app, make sure to <a href="/react/docs/installation.html#development-and-production-versions">compile it in production mode</a>.</p>

<p>In case you don&#39;t use a bundler, we also provide pre-built bundles in the npm packages which you can <a href="/react/docs/installation.html#using-a-cdn">include as script tags</a> on your page:</p>

<ul>
<li><strong>React</strong><br>
Dev build with warnings: <a href="https://unpkg.com/react@15.4.0/dist/react.js">react/dist/react.js</a><br>
Minified build for production: <a href="https://unpkg.com/react@15.4.0/dist/react.min.js">react/dist/react.min.js</a><br></li>
<li><strong>React with Add-Ons</strong><br>
Dev build with warnings: <a href="https://unpkg.com/react@15.4.0/dist/react-with-addons.js">react/dist/react-with-addons.js</a><br>
Minified build for production: <a href="https://unpkg.com/react@15.4.0/dist/react-with-addons.min.js">react/dist/react-with-addons.min.js</a><br></li>
<li><strong>React DOM</strong> (include React in the page before React DOM)<br>
Dev build with warnings: <a href="https://unpkg.com/react-dom@15.4.0/dist/react-dom.js">react-dom/dist/react-dom.js</a><br>
Minified build for production: <a href="https://unpkg.com/react-dom@15.4.0/dist/react-dom.min.js">react-dom/dist/react-dom.min.js</a><br></li>
<li><strong>React DOM Server</strong> (include React in the page before React DOM Server)<br>
Dev build with warnings: <a href="https://unpkg.com/react-dom@15.4.0/dist/react-dom-server.js">react-dom/dist/react-dom-server.js</a><br>
Minified build for production: <a href="https://unpkg.com/react-dom@15.4.0/dist/react-dom-server.min.js">react-dom/dist/react-dom-server.min.js</a></li>
</ul>

<p>We&#39;ve also published version <code>15.4.0</code> of the <code>react</code>, <code>react-dom</code>, and addons packages on npm and the <code>react</code> package on bower.</p>

<hr>

<h2>Changelog</h2>

<h3>React</h3>

<ul>
<li>React package and browser build no longer &quot;secretly&quot; includes React DOM.<br>
<small>(<a href="https://github.com/sebmarkbage">@sebmarkbage</a> in <a href="https://github.com/facebook/react/pull/7164">#7164</a> and <a href="https://github.com/facebook/react/pull/7168">#7168</a>)</small></li>
<li>Required PropTypes now fail with specific messages for null and undefined.<br>
<small>(<a href="https://github.com/chenglou">@chenglou</a> in <a href="https://github.com/facebook/react/pull/7291">#7291</a>)</small></li>
<li>Improved development performance by freezing children instead of copying.<br>
<small>(<a href="https://github.com/keyanzhang">@keyanzhang</a> in <a href="https://github.com/facebook/react/pull/7455">#7455</a>)</small></li>
</ul>

<h3>React DOM</h3>

<ul>
<li>Fixed occasional test failures when React DOM is used together with shallow renderer.<br>
<small>(<a href="https://github.com/goatslacker">@goatslacker</a> in <a href="https://github.com/facebook/react/pull/8097">#8097</a>)</small></li>
<li>Added a warning for invalid <code>aria-</code> attributes.<br>
<small>(<a href="https://github.com/jessebeach">@jessebeach</a> in <a href="https://github.com/facebook/react/pull/7744">#7744</a>)</small></li>
<li>Added a warning for using <code>autofocus</code> rather than <code>autoFocus</code>.<br>
<small>(<a href="https://github.com/hkal">@hkal</a> in <a href="https://github.com/facebook/react/pull/7694">#7694</a>)</small></li>
<li>Removed an unnecessary warning about polyfilling <code>String.prototype.split</code>.<br>
<small>(<a href="https://github.com/nhunzaker">@nhunzaker</a> in <a href="https://github.com/facebook/react/pull/7629">#7629</a>)</small></li>
<li>Clarified the warning about not calling PropTypes manually.<br>
<small>(<a href="https://github.com/jedwards1211">@jedwards1211</a> in <a href="https://github.com/facebook/react/pull/7777">#7777</a>)</small></li>
<li>The unstable <code>batchedUpdates</code> API now passes the wrapped function&#39;s return value through.<br>
<small>(<a href="https://github.com/bgnorlov">@bgnorlov</a> in <a href="https://github.com/facebook/react/pull/7444">#7444</a>)</small></li>
<li>Fixed a bug with updating text in IE 8.<br>
<small>(<a href="https://github.com/mnpenner">@mnpenner</a> in <a href="https://github.com/facebook/react/pull/7832">#7832</a>)</small></li>
</ul>

<h3>React Perf</h3>

<ul>
<li>When ReactPerf is started, you can now view the relative time spent in components as a chart in Chrome Timeline.<br>
<small>(<a href="https://github.com/gaearon">@gaearon</a> in <a href="https://github.com/facebook/react/pull/7549">#7549</a>)</small></li>
</ul>

<h3>React Test Utils</h3>

<ul>
<li>If you call <code>Simulate.click()</code> on a <code>&lt;input disabled onClick={foo} /&gt;</code> then <code>foo</code> will get called whereas it didn&#39;t before.<br>
<small>(<a href="https://github.com/nhunzaker">@nhunzaker</a> in <a href="https://github.com/facebook/react/pull/7642">#7642</a>)</small></li>
</ul>

<h3>React Test Renderer</h3>

<ul>
<li>Due to packaging changes, it no longer crashes when imported together with React DOM in the same file.<br>
<small>(<a href="https://github.com/sebmarkbage">@sebmarkbage</a> in <a href="https://github.com/facebook/react/pull/7164">#7164</a> and <a href="https://github.com/facebook/react/pull/7168">#7168</a>)</small></li>
<li><code>ReactTestRenderer.create()</code> now accepts <code>{createNodeMock: element =&gt; mock}</code> as an optional argument so you can mock refs with snapshot testing.<br>
<small>(<a href="https://github.com/Aweary">@Aweary</a> in <a href="https://github.com/facebook/react/pull/7649">#7649</a> and <a href="https://github.com/facebook/react/pull/8261">#8261</a>)</small></li>
</ul>

</div>


  <div class="fb-like" data-send="true" data-width="650" data-show-faces="false"></div>


  </div>
  <div class="nav-docs nav-blog">
  <div class="nav-docs-section">
    <h3>Recent posts</h3>
    <ul>
      
        <li><a href="/react/blog/2017/04/07/react-v15.5.0.html">React v15.5.0</a></li>
      
        <li><a href="/react/blog/2016/11/16/react-v15.4.0.html" class="active">React v15.4.0</a></li>
      
        <li><a href="/react/blog/2016/09/28/our-first-50000-stars.html">Our First 50,000 Stars</a></li>
      
        <li><a href="/react/blog/2016/08/05/relay-state-of-the-state.html">Relay: State of the State</a></li>
      
        <li><a href="/react/blog/2016/07/22/create-apps-with-no-configuration.html">Create Apps with No Configuration</a></li>
      
        <li><a href="/react/blog/2016/07/13/mixins-considered-harmful.html">Mixins Considered Harmful</a></li>
      
        <li><a href="/react/blog/2016/07/11/introducing-reacts-error-code-system.html">Introducing React's Error Code System</a></li>
      
        <li><a href="/react/blog/2016/04/08/react-v15.0.1.html">React v15.0.1</a></li>
      
        <li><a href="/react/blog/2016/04/07/react-v15.html">React v15.0</a></li>
      
        <li><a href="/react/blog/2016/03/29/react-v0.14.8.html">React v0.14.8</a></li>
      
      <li><a href="/react/blog/all.html">All posts ...</a></li>
    </ul>
  </div>
</div>

</section>


    <footer class="nav-footer">
  <section class="sitemap">
    <a href="/react/" class="nav-home">
    </a>
    <div>
      <h5><a href="/react/docs/">Docs</a></h5>
      <a href="/react/docs/hello-world.html">Quick Start</a>
      <a href="/react/docs/thinking-in-react.html">Thinking in React</a>
      <a href="/react/tutorial/tutorial.html">Tutorial</a>
      <a href="/react/docs/jsx-in-depth.html">Advanced Guides</a>
    </div>
    <div>
      <h5><a href="/react/community/support.html">Community</a></h5>
      <a href="http://stackoverflow.com/questions/tagged/reactjs" target="_blank">Stack Overflow</a>
      <a href="https://discuss.reactjs.org/" target="_blank">Discussion Forum</a>
      <a href="https://discord.gg/0ZcbPKXt5bZjGY5n" target="_blank">Reactiflux Chat</a>
      <a href="https://www.facebook.com/react" target="_blank">Facebook</a>
      <a href="https://twitter.com/reactjs" target="_blank">Twitter</a>
    </div>
    <div>
      <h5><a href="/react/community/support.html">Resources</a></h5>
      <a href="/react/community/conferences.html">Conferences</a>
      <a href="/react/community/videos.html">Videos</a>
      <a href="https://github.com/facebook/react/wiki/Examples" target="_blank">Examples</a>
      <a href="https://github.com/facebook/react/wiki/Complementary-Tools" target="_blank">Complementary Tools</a>
    </div>
    <div>
      <h5>More</h5>
      <a href="/react/blog/">Blog</a>
      <a href="https://github.com/facebook/react" target="_blank">GitHub</a>
      <a href="http://facebook.github.io/react-native/" target="_blank">React Native</a>
      <a href="/react/acknowledgements.html">Acknowledgements</a>
    </div>
  </section>
  <a href="https://code.facebook.com/projects/" target="_blank" class="fbOpenSource">
    <img src="/react/img/oss_logo.png" alt="Facebook Open Source" width="170" height="45"/>
  </a>
  <section class="copyright">
    Copyright © 2017 Facebook Inc.
  </section>
</footer>

  </div>

  <div id="fb-root"></div>
  <script src="/react/js/anchor-links.js"></script>
  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
    ga('create', 'UA-41298772-1', 'facebook.github.io');
    ga('send', 'pageview');

    !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="https://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");

    (function(d, s, id) {
      var js, fjs = d.getElementsByTagName(s)[0];
      if (d.getElementById(id)) return;
      js = d.createElement(s); js.id = id;
      js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.6&appId=623268441017527";
      fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));

    docsearch({
      apiKey: '36221914cce388c46d0420343e0bb32e',
      indexName: 'react',
      inputSelector: '#algolia-doc-search'
    });
  </script>
</body>
</html>
